package com.jzqf.bluetooth.server

import android.app.Service
import android.bluetooth.*
import android.bluetooth.le.AdvertiseCallback
import android.bluetooth.le.AdvertiseData
import android.bluetooth.le.AdvertiseSettings
import android.content.Context
import android.content.Intent
import android.content.pm.PackageManager
import android.os.IBinder
import android.os.ParcelUuid
import android.util.Log
import com.jzqf.bluetooth.Api
import com.jzqf.bluetooth.Constants
import com.jzqf.bluetooth.event.EventCode
import com.jzqf.bluetooth.event.EventMessage
import org.greenrobot.eventbus.EventBus
import kotlin.math.ceil

/**
 * 蓝牙BLE服务端
 * 2020/9/25 9:15
 * @author LiuWeiHao
 */
class BleService : Service() {
    private val TAG = "【BleService】"
    private var bluetoothManager: BluetoothManager? = null
    private var bluetoothAdapter: BluetoothAdapter? = null
    private var bluetoothGattServer: BluetoothGattServer? = null
    private var number: Int = 0
    private var responseData: StringBuilder = StringBuilder()
    private var startTime = 0L

    override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
        number = intent?.getIntExtra("number", 0)!!
        bluetoothManager = getSystemService(Context.BLUETOOTH_SERVICE) as BluetoothManager
        bluetoothAdapter = bluetoothManager?.adapter
        initServer()
        return super.onStartCommand(intent, flags, startId)
    }

    private fun initServer() {
        if (bluetoothAdapter == null || bluetoothAdapter?.isEnabled == false) {
//            val intentBlue = Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE)
//            context.startActivityForResult(intentBlue, REQUEST_CODE_BLUE)
            Log.d(TAG, "蓝牙未开启")
            bluetoothAdapter?.enable()
            return
        }
        if (!packageManager.hasSystemFeature(PackageManager.FEATURE_BLUETOOTH_LE)) {
            Log.e(TAG, "设备不支持BLE")
            EventBus.getDefault().post(EventMessage(EventCode.RESULT, "设备不支持BLE"))
            return
        }
        startTime = System.currentTimeMillis()
        val settings = AdvertiseSettings.Builder()
            .setConnectable(true)
            .setAdvertiseMode(AdvertiseSettings.ADVERTISE_MODE_LOW_LATENCY)
            .build()

        val advertiseData = AdvertiseData.Builder()
            .setIncludeDeviceName(true)
            .setIncludeTxPowerLevel(true)
            .build()

        //通过UUID_SERVICE构建
        val scanResponseData = AdvertiseData.Builder()
            .addServiceUuid(ParcelUuid(Api.UUID_SERVICE))
            .setIncludeTxPowerLevel(true)
            .build()
        val bluetoothLeAdvertiser = bluetoothAdapter!!.bluetoothLeAdvertiser
        if (bluetoothLeAdvertiser == null) {
            EventMessage(
                EventCode.RESULT, "bluetoothLeAdvertiser is null!\n 设备不支持BLE"
            )
            return
        }
        if (settings == null) {
            EventMessage(
                EventCode.RESULT, "settings is null!"
            )
            return
        }
        if (advertiseData == null) {
            EventMessage(
                EventCode.RESULT, "advertiseData is null!"
            )
            return
        }
        if (scanResponseData == null) {
            EventMessage(
                EventCode.RESULT, "scanResponseData is null!"
            )
            return
        }
        bluetoothLeAdvertiser.startAdvertising(
            settings,
            advertiseData,
            scanResponseData,
            advertiseCallback
        )
    }

    private val advertiseCallback = object : AdvertiseCallback() {
        override fun onStartSuccess(settingsInEffect: AdvertiseSettings?) {
            super.onStartSuccess(settingsInEffect)
            Log.d(TAG, "onStartSuccess ")
            close()
            initService()
        }

        override fun onStartFailure(errorCode: Int) {
            super.onStartFailure(errorCode)
            Log.e(TAG, "onStartFailure errorCode=$errorCode")
        }
    }

    private fun initService() {
        bluetoothGattServer = bluetoothManager?.openGattServer(this, bluetoothGattServerCallback)
        //指定创建UUID的服务
        val bluetoothGattService =
            BluetoothGattService(Api.UUID_SERVICE, BluetoothGattService.SERVICE_TYPE_PRIMARY)
        //添加指定UUID的可读characteristic
        val characteristicRead = BluetoothGattCharacteristic(
            Api.UUID_CHARACTERISTIC_READ,
            BluetoothGattCharacteristic.PROPERTY_READ,
            BluetoothGattCharacteristic.PERMISSION_READ
        )
        //添加可读characteristic的descriptor
        val bluetoothGattDescriptor =
            BluetoothGattDescriptor(Api.UUID_DESCRIPTOR, BluetoothGattDescriptor.PERMISSION_WRITE)
        characteristicRead.addDescriptor(bluetoothGattDescriptor)
        bluetoothGattService.addCharacteristic(characteristicRead)
        //添加指定UUID的可写characteristic
        val characteristicWrite = BluetoothGattCharacteristic(
            Api.UUID_CHARACTERISTIC_WRITE,
            BluetoothGattCharacteristic.PROPERTY_WRITE or BluetoothGattCharacteristic.PROPERTY_READ
                    or BluetoothGattCharacteristic.PROPERTY_NOTIFY,
            BluetoothGattCharacteristic.PERMISSION_WRITE
        )
        bluetoothGattService.addCharacteristic(characteristicWrite)
        val characteristicNotif = BluetoothGattCharacteristic(
            Api.UUID_NOTIFY,
            BluetoothGattCharacteristic.PROPERTY_NOTIFY,
            BluetoothGattCharacteristic.PERMISSION_WRITE
        )
        bluetoothGattService.addCharacteristic(characteristicNotif)
        bluetoothGattServer?.addService(bluetoothGattService)
//        bluetoothGattServer?.addService(BluetoothGattService(Api.UUID_DESCRIPTOR, BluetoothGattService.SERVICE_TYPE_PRIMARY))
//        val timer=Timer()
//         timer.schedule(object : TimerTask() {
//            override fun run() {
//                bluetoothGattServer?.addService(bluetoothGattService)
//            }
//        }, 200)

    }

    private val bluetoothGattServerCallback = object : BluetoothGattServerCallback() {
        override fun onConnectionStateChange(device: BluetoothDevice?, status: Int, newState: Int) {
            super.onConnectionStateChange(device, status, newState)
            Log.d(TAG, "onConnectionStateChange name=${device?.name} MAC=${device?.address}")
            if (status == BluetoothGatt.GATT_SUCCESS) {
                when (newState) {
                    BluetoothProfile.STATE_CONNECTED -> {
                        EventBus.getDefault().post(
                            EventMessage(
                                EventCode.RESULT, "设备连接成功" +
                                        "\n name=${device?.name} \n MAC=${device?.address}"
                            )
                        )
                    }
                    BluetoothProfile.STATE_DISCONNECTING -> {
                        EventBus.getDefault().post(EventMessage(EventCode.RESULT, "设备连接中..."))
                    }
                    BluetoothProfile.STATE_DISCONNECTED -> {
                        EventBus.getDefault().post(EventMessage(EventCode.RESULT, "设备已断开连接"))
//                        val remoteDevice = bluetoothAdapter?.getRemoteDevice(Api.address)
//                        bluetoothGattServer?.cancelConnection(remoteDevice)
                    }
                }
            } else {
                EventBus.getDefault().post(EventMessage(EventCode.RESULT, "设备连接失败:status=$status"))
            }
        }

        /**
         * 指示是否已成功添加本地服务。
         */
        override fun onServiceAdded(status: Int, service: BluetoothGattService?) {
            super.onServiceAdded(status, service)
            Log.d(
                TAG,
                "onServiceAdded time=${System.currentTimeMillis() - startTime},status=$status,service ${service?.uuid}"
            )
            if (status == BluetoothGatt.GATT_SUCCESS) {
                EventBus.getDefault()
                    .post(
                        EventMessage(
                            EventCode.RESULT, "服务已开启" +
                                    "\n service uuid=${service?.uuid}"
                        )
                    )
            } else {
                EventBus.getDefault()
                    .post(EventMessage(EventCode.RESULT, "服务开启失败"))
            }
        }

        /**
         * 远程客户端已请求读取本地特征。
         */
        override fun onCharacteristicReadRequest(
            device: BluetoothDevice?,
            requestId: Int,
            offset: Int,
            characteristic: BluetoothGattCharacteristic?
        ) {
//            super.onCharacteristicReadRequest(device, requestId, offset, characteristic)
            Log.d(TAG, "onCharacteristicReadRequest name=${device?.name} MAC=${device?.address}")
            bluetoothGattServer?.sendResponse(
                device,
                requestId,
                BluetoothGatt.GATT_SUCCESS,
                offset,
                characteristic!!.value
            )
        }

        /**
         * 远程客户端已请求写入本地特征。
         */
        override fun onCharacteristicWriteRequest(
            device: BluetoothDevice?,
            requestId: Int,
            characteristic: BluetoothGattCharacteristic?,
            preparedWrite: Boolean,
            responseNeeded: Boolean,
            offset: Int,
            value: ByteArray?
        ) {
            super.onCharacteristicWriteRequest(
                device,
                requestId,
                characteristic,
                preparedWrite,
                responseNeeded,
                offset,
                value
            )
            Log.d(
                TAG, "onCharacteristicWriteRequest name=${device?.name} MAC=${device?.address} " +
                        "\n uuid=${characteristic?.uuid}" +
                        "\n properties=${characteristic?.properties}" +
                        "\n permissions=${characteristic?.permissions}"
            )

            bluetoothGattServer?.sendResponse(
                device,
                requestId,
                BluetoothGatt.GATT_SUCCESS,
                offset,
                value
            )
            //处理响应内容
            onResponseToClient(value!!, device!!, requestId, characteristic)
        }

        /**
         * 远程客户端已请求读取本地描述符。
         */
        override fun onDescriptorReadRequest(
            device: BluetoothDevice?,
            requestId: Int,
            offset: Int,
            descriptor: BluetoothGattDescriptor?
        ) {
            super.onDescriptorReadRequest(device, requestId, offset, descriptor)
            Log.d(TAG, "onDescriptorReadRequest name=${device?.name} MAC=${device?.address}")
            bluetoothGattServer?.sendResponse(
                device,
                requestId,
                BluetoothGatt.GATT_SUCCESS,
                offset,
                null
            )
        }

        /**
         * 远程客户端已请求写入本地描述符。
         */
        override fun onDescriptorWriteRequest(
            device: BluetoothDevice?,
            requestId: Int,
            descriptor: BluetoothGattDescriptor?,
            preparedWrite: Boolean,
            responseNeeded: Boolean,
            offset: Int,
            value: ByteArray?
        ) {
            super.onDescriptorWriteRequest(
                device,
                requestId,
                descriptor,
                preparedWrite,
                responseNeeded,
                offset,
                value
            )
            Log.d(TAG, "onDescriptorWriteRequest")
            bluetoothGattServer?.sendResponse(
                device,
                requestId,
                BluetoothGatt.GATT_SUCCESS,
                offset,
                value
            )
        }

        /**
         * 当通知或指示已发送到远程设备时调用回调。
         */
        override fun onNotificationSent(device: BluetoothDevice?, status: Int) {
//            Log.d(
//                TAG,
//                "onNotificationSent status=$status,name=${device?.name} MAC=${device?.address}"
//            )
            super.onNotificationSent(device, status)
        }

        /**
         * 指示给定设备连接的MTU的回调已更改。
         */
        override fun onMtuChanged(device: BluetoothDevice?, mtu: Int) {
            super.onMtuChanged(device, mtu)
            Log.d(TAG, "onMtuChanged mtu=$mtu")
        }

        /**
         * 执行此设备的所有挂起的写操作。
         */
        override fun onExecuteWrite(device: BluetoothDevice?, requestId: Int, execute: Boolean) {
            super.onExecuteWrite(device, requestId, execute)
            Log.d(TAG, "onExecuteWrite")
        }

    }

    /**
     * 处理响应内容
     *
     * @param responseByteArray 响应的字节数组
     * @param device 设备
     * @param requestId 请求ID
     * @param characteristic 特征值
     */
    private fun onResponseToClient(
        responseByteArray: ByteArray,
        device: BluetoothDevice,
        requestId: Int,
        characteristic: BluetoothGattCharacteristic?
    ) {
        if (!dealResponseData(responseByteArray)) {
            Log.d(
                TAG, "onResponseToClient " +
                        " requestId=$requestId 处理后的消息:$responseData"
            )
            return
        }
        EventBus.getDefault().post(EventMessage(EventCode.RESULT, "服务端收到:\n$responseData"))
        when (responseData.toString()) {
            Api.searchList -> {
                writeData(Constants.data(number), device, characteristic)
            }
            else -> {
                writeData(Constants.data(number), device, characteristic)
            }
        }
    }

    /**
     * 根据每次返回的字节数拼接数据
     * 拼接完成返回true，否则返回false
     * @param responseByteArray 收到的字节数组
     */
    private fun dealResponseData(responseByteArray: ByteArray): Boolean {
        var resultStr = String(responseByteArray)
        Log.d(
            TAG, "收到的原始消息:$resultStr"
        )
        val list = mutableListOf(
            Charsets.UTF_8, Charsets.ISO_8859_1,
            Charsets.US_ASCII, Charsets.UTF_16, Charsets.UTF_16BE, Charsets.UTF_16LE,
            Charsets.UTF_32, Charsets.UTF_32BE, Charsets.UTF_32LE
        )
        list.forEach {
            Log.d(TAG, "解码数据:${it}-->${String(responseByteArray, it)}")
        }
        if (resultStr.contains(Api.FLAG_START) || resultStr.contains(Api.FLAG_END)) {
            if (resultStr.contains(Api.FLAG_START) && resultStr.contains(Api.FLAG_END)) {
                //首次接收清除缓存
                responseData.clear()
                resultStr = resultStr.replace(Api.FLAG_START, "")
                resultStr = resultStr.replace(Api.FLAG_END, "")
                responseData.append(resultStr)
                return true
            }
            if (resultStr.contains(Api.FLAG_START)) {
                //首次接收清除缓存
                responseData.clear()
                responseData.append(resultStr.replace(Api.FLAG_START, ""))
            }
            if (resultStr.contains(Api.FLAG_END)) {
                responseData.append(resultStr.replace(Api.FLAG_END, ""))
                return true
            }
        } else {
            responseData.append(resultStr)
            EventBus.getDefault().post(EventMessage(EventCode.RESULT, "服务端收到:\n$responseData"))
        }
        return true
    }

    /**
     * 写入数据
     * @param data 待写入的字符串
     * @param device 设备
     * @param characteristic 特征值
     */
    private fun writeData(
        data: String,
        device: BluetoothDevice,
        characteristic: BluetoothGattCharacteristic?
    ) {
        if (characteristic == null) {
            return
        }
        //拼接前后缀
        val newData = "${Api.FLAG_START}$data${Api.FLAG_END}"
        //将给定的特性及其值写入关联的远程设备。
        if (newData.length > Api.MAX_MTU) {
            var tempStr: String?
            for (i in 0..newData.length / Api.MAX_MTU) {
                tempStr =
                    if (i == ceil((newData.length / Api.MAX_MTU).toDouble()).toInt()) {
                        newData.substring(i * Api.MAX_MTU, newData.length)
                    } else {
                        newData.substring(i * Api.MAX_MTU, (i + 1) * Api.MAX_MTU)
                    }
                characteristic.setValue(tempStr)
                val notifyCharacteristicChanged =
                    bluetoothGattServer?.notifyCharacteristicChanged(device, characteristic, false)
                Log.d(TAG, "要发送的数据 $notifyCharacteristicChanged $tempStr")
                //等待此次发送完毕才执行下一次发送，否则写入失败
                Thread.sleep(Api.DELAY_SEND)
            }
        } else {
            characteristic.setValue(newData)
            val notifyCharacteristicChanged =
                bluetoothGattServer?.notifyCharacteristicChanged(device, characteristic, false)
            Log.d(TAG, "notifyCharacteristicChanged=$notifyCharacteristicChanged")
        }
    }


    override fun onBind(intent: Intent?): IBinder? {
        return null
    }

    fun close() {
        bluetoothGattServer?.close()
    }
}